package org.geotools.tutorial.quickstart.Utilities;

import org.geotools.data.DataUtilities;
import org.geotools.data.Query;
import org.geotools.data.QueryCapabilities;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.store.EmptyFeatureCollection;
import org.geotools.data.store.ReTypingFeatureCollection;
import org.geotools.data.store.ReprojectingFeatureCollection;
import org.geotools.feature.collection.DecoratingSimpleFeatureCollection;
import org.geotools.feature.collection.FilteringSimpleFeatureCollection;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.filter.Filter;
import org.opengis.filter.sort.SortBy;

/**
 * @author
 * @DesktopJavaDocable disable
 */
public class FeatureCollectionStore {
	private SimpleFeatureCollection collection;
	private QueryCapabilities capabilities;

	public FeatureCollectionStore(SimpleFeatureCollection collection) {
		this.collection = collection;
	}

	public SimpleFeatureType getSchema() {
		return this.collection.getSchema();
	}

	public synchronized QueryCapabilities getQueryCapabilities() {
		if (this.capabilities == null) {
			this.capabilities = new QueryCapabilities() {
				public boolean isOffsetSupported() {
					return true;
				}

				public boolean isReliableFIDSupported() {
					return true;
				}

				public boolean supportsSorting(SortBy[] sortAttributes) {
					return true;
				}
			};
		}

		return this.capabilities;
	}

	public SimpleFeatureCollection getFeatures(Query query) {
		query = DataUtilities.resolvePropertyNames(query, this.getSchema());
		int offset = query.getStartIndex() != null ? query.getStartIndex() : 0;
		//if (offset > 0 & query.getSortBy() == null) {
		//	if (!this.getQueryCapabilities().supportsSorting(query.getSortBy())) {
		//		throw new IllegalStateException("Feature source does not support this sorting so there is no way a stable paging (offset/limit) can be performed");
		//	}
		//
		//	Query copy = new Query(query);
		//	copy.setSortBy(new SortBy[]{SortBy.NATURAL_ORDER});
		//	query = copy;
		//}

		SimpleFeatureCollection features = this.collection;
		if (query.getFilter() != null && query.getFilter().equals(Filter.EXCLUDE)) {
			return new EmptyFeatureCollection(this.getSchema());
		} else {
			if (query.getFilter() != null && query.getFilter() != Filter.INCLUDE) {
				features = new FilteringSimpleFeatureCollection(features, query.getFilter());
			}

			if (query.getCoordinateSystemReproject() != null) {
				features = new ReprojectingFeatureCollection(features, query.getCoordinateSystemReproject());
			}

			//if (offset > 0 || !query.isMaxFeaturesUnlimited()) {
			//	long max = 9223372036854775807L;
			//	if (!query.isMaxFeaturesUnlimited()) {
			//		max = (long) query.getMaxFeatures();
			//	}
			//
			//	features = new MaxSimpleFeatureCollection(features, (long) offset, max);
			//}

			if (query.getPropertyNames() != Query.ALL_NAMES) {
				SimpleFeatureType schema = features.getSchema();
				SimpleFeatureType target = SimpleFeatureTypeBuilder.retype(schema, query.getPropertyNames());
				if (!target.equals(schema)) {
					features = new ReTypingFeatureCollection(features, target);
				}
			}

			return new FeatureCollectionStore.SubCollection(query, features);
		}
	}

	protected class SubCollection extends DecoratingSimpleFeatureCollection {
		private Query query;

		protected SubCollection(Query query, SimpleFeatureCollection features) {
			super(features);
			this.query = query;
		}

		public SimpleFeatureCollection subCollection(Filter filter) {
			Query q = new Query(this.getSchema().getTypeName(), filter);
			Query subQuery = DataUtilities.mixQueries(this.query, q, q.getHandle());
			return FeatureCollectionStore.this.getFeatures(subQuery);
		}

		public SimpleFeatureCollection sort(SortBy order) {
			Query q = new Query(this.getSchema().getTypeName());
			q.setSortBy(new SortBy[]{order});
			Query subQuery = DataUtilities.mixQueries(this.query, q, q.getHandle());
			return FeatureCollectionStore.this.getFeatures(subQuery);
		}
	}
}
